package com.unieagle.exam.http;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import android.util.Log;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.ServerError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.unieagle.exam.app.ExamApplication;

public class VolleyRequest {
    private static final String TAG = "VolleyRequest";

    private static VolleyRequest instance;

    private RequestQueue mQueue;

    private static RetryPolicy SDefaultRetryPolicy =  new DefaultRetryPolicy(5000, 0,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);

    public static VolleyRequest getInstance(){
        if(instance == null) {
            synchronized (VolleyRequest.class){
                if(instance == null){
                    instance = new VolleyRequest();
                }
            }
        }
        return instance;
    }

    private VolleyRequest() {
        mQueue = Volley.newRequestQueue(ExamApplication.getAppContext());
    }

    public RetryPolicy createPolicy(int initialTimeoutMs, int maxNumRetries){
        return new DefaultRetryPolicy(initialTimeoutMs, maxNumRetries,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
    }

    /**
     * 开始下载数据
     */
    public void request(VolleyTask volleyTask) {
        if(volleyTask == null){
            Log.d(TAG, "request: null parameter");
            return;
        }
        Request request = createRequest(volleyTask);
        if(request == null){
            Log.d(TAG, "request: create request:" + volleyTask.getRequestClass().getName() + " fail");
            return ;
        }
        mQueue.add(request);
    }

    /**
     * 取消下载
     */
    public void stop() {
        if (mQueue != null) {
            mQueue.stop();
        }
    }

    private Request createRequest(VolleyTask task){
        Request request = null;
        try {
            Constructor<? extends Request> constructor =  task.getRequestClass().getConstructor(VolleyTask.class);
            request = constructor.newInstance(task);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return request;
    }

    public static class FormatGsonRequest extends Request<Object> {

        private final Gson gson = new Gson();
        private final VolleyTask volleyTask;

        public FormatGsonRequest(VolleyTask volleyTask) {
            super(volleyTask.getMethod(), volleyTask.getUrl(), volleyTask.getErrorListener());
            this.volleyTask = volleyTask;
            if(volleyTask.getPolocy() != null){
                setRetryPolicy(volleyTask.getPolocy());
            }else{
                setRetryPolicy(VolleyRequest.SDefaultRetryPolicy);
            }
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            return volleyTask.getHeaders() != null ? volleyTask.getHeaders() : super.getHeaders();
        }

        @Override
        protected Response<Object> parseNetworkResponse(NetworkResponse response) {
            try {
                String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                Log.d("FormatGsonRequest", "response json:" + json);
                Object fromJson = gson.fromJson(json, volleyTask.getResponseType());
                return Response.success(fromJson, HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            } catch (JsonSyntaxException e) {
                return Response.error(new ParseError(e));
            }
        }

        @Override
        protected void deliverResponse(Object response) {
            if (volleyTask.getListener() != null) {
                volleyTask.getListener().onResponse(response);
            }

        }

        @Override
        public void deliverError(VolleyError error) {
            if(error instanceof ServerError){
                if( error.networkResponse.statusCode == 201){
                    if (volleyTask.getListener() != null) {
                        volleyTask.getListener().onResponse(parseNetworkResponse(error.networkResponse));
                        return;
                    }
                }
            }
            super.deliverError(error);
        }

    }

    public static class GsonGsonRequest extends JsonRequest<Object>{

        private final Gson gson = new Gson();
        private final VolleyTask volleyTask;

        public GsonGsonRequest(VolleyTask volleyTask) {
            super(volleyTask.getMethod(), volleyTask.getUrl(), volleyTask.getContent(),volleyTask.getListener(), volleyTask.getErrorListener());
            this.volleyTask = volleyTask;
            if(volleyTask.getPolocy() != null){
                setRetryPolicy(volleyTask.getPolocy());
            }else{
                setRetryPolicy(VolleyRequest.SDefaultRetryPolicy);
            }
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> headers = volleyTask.getHeaders();
            if(headers == null){
                headers = new HashMap<String, String>();
            }
            headers.put("Accept", "application/json");
            headers.put("Content-Type", "application/json; charset=UTF-8");
            return headers;
        }

        @Override
        protected Response<Object> parseNetworkResponse(NetworkResponse response) {
            try {
                String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                Log.d("FormatGsonRequest", "response json:" + json);
                Object fromJson = gson.fromJson(json, volleyTask.getResponseType());
                return Response.success(fromJson, HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            } catch (JsonSyntaxException e) {
                return Response.error(new ParseError(e));
            }
        }

        @Override
        protected void deliverResponse(Object response) {
            if (volleyTask.getListener() != null) {
                volleyTask.getListener().onResponse(response);
            }

        }

        @Override
        public void deliverError(VolleyError error) {
            if(error instanceof ServerError){
                if( error.networkResponse.statusCode == 201){
                    if (volleyTask.getListener() != null) {
                        volleyTask.getListener().onResponse(parseNetworkResponse(error.networkResponse));
                        return;
                    }
                }
            }
            super.deliverError(error);
        }
    }

}

